﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#include "stdafx.h"
#include "CenterServerImp.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// CCenterServer
UInt CCenterServer::Command(PCXStr pszCMD, uintptr_t utParam)
{
    CString strCmd = pszCMD;
    if (strCmd == TF("ServerInfo"))
    {
        m_nServerInfo = (Int)utParam;
    }
    else if (strCmd == TF("CommonEvent"))
    {
        m_nCommonEvent = (Int)utParam;
    }
    return (UInt)RET_OKAY;
}

UInt CCenterServer::Update(void)
{
    if (m_nStatus < STATUSS_ERROR)
    {
        if (m_NetworkPtr->Check(m_pConfig->GetUpdateTick() * DATAD_TIME))
        {
            m_Server[PAKT_CENTER].MayDay(); // 网络工作线程异常
            m_nStatus = STATUSS_ERROR;
            DEV_ERROR(TF("[同步管理]网络线程异常, 进入异常状态"));
            LOG_ERROR(m_FileLog, TF("[同步管理]网络线程异常, 进入异常状态"));
        }
        CheckListen();
        m_RoutinePtr->Update();
        if (SyncServersInfo())
        {
            // mayday : network & tick thread exception
            // warn   : tcp listen
            return RET_OKAY;
        }
    }
    return RET_FAIL;
}
//--------------------------------------
UInt CCenterServer::Init(CEventHandler& EventHandlerRef, CServerConfig& ConfigRef)
{
    if (m_nStatus == STATUSS_NONE)
    {
        m_FileLog.Create(ConfigRef.GetLogPath(), CServerConfig::CenterServer);
        LOG_INFO(m_FileLog, TF("[同步管理]初始化开始!"));
        m_MgrHandler = &EventHandlerRef;
        m_pConfig    = &ConfigRef;

        if (LoadConfig() == false)
        {
            return (UInt)RET_FAIL;
        }
        m_nStatus = STATUSS_INIT;
        LOG_INFO(m_FileLog, TF("[同步管理]初始化完成!"));
        return (UInt)RET_OKAY;
    }
    return (UInt)RET_FAIL;
}

bool CCenterServer::LoadConfig(void)
{
    assert(m_pConfig != nullptr);
    m_pConfig->Dump(m_FileLog, CServerConfig::CFG_LOAD_CENTER); // 配置信息输出到日志文件

    // 从动态变量表获取网络层智能指针
    assert(m_NetworkPtr == nullptr);
    CKeyValue::VALUE xValue = { 0 };
    m_pConfig->GetKeyValue().GetValue(CServerConfig::NetworkPtr, xValue);
    if (xValue.pValue == nullptr)
    {
        LOG_ERROR(m_FileLog, TF("[同步管理]从动态变量表获取网络层智能指针无效"));
        return false;
    }
    m_NetworkPtr = *(reinterpret_cast<CNetworkPtr*>(xValue.pValue));
    // 保存同步管理指针到动态变量表
    m_pConfig->GetKeyValue().AddItem(CServerConfig::CenterServer, this);

    assert(m_sListenInternal  == 0);

    assert(m_Balance.SvrMap.GetSize()  == 0);
    assert(m_AuthorDB.SvrMap.GetSize() == 0);
    assert(m_Author.SvrMap.GetSize()   == 0);
    assert(m_MasterDB.SvrMap.GetSize() == 0);
    assert(m_Master.SvrMap.GetSize()   == 0);

    m_Server[PAKT_CENTER].usId   = m_pConfig->GetServerId(CServerConfig::CFG_LOAD_CENTER);
    m_Server[PAKT_CENTER].usIncr = m_pConfig->GetServerIncr(CServerConfig::CFG_LOAD_CENTER);
    m_Server[PAKT_CENTER].ClearLoad(); // 更新控制台信息
    LOGV_INFO(m_FileLog, TF("[同步管理]从配置读取服务器Id=%d, Incr=%d!"), m_Server[PAKT_CENTER].usId, m_Server[PAKT_CENTER].usIncr);
    // 将同步管理id通过统计信息发送给授权均衡和授权网关
    m_Server[PAKT_BALANCE].usId  = m_Server[PAKT_CENTER].usId;
    m_Server[PAKT_AUTHORDB].usId = m_Server[PAKT_CENTER].usId;
    m_Server[PAKT_AUTHOR].usId   = m_Server[PAKT_CENTER].usId;
    m_Server[PAKT_MASTERDB].usId = m_Server[PAKT_CENTER].usId;
    m_Server[PAKT_MASTER].usId   = m_Server[PAKT_CENTER].usId;

    if (LoadExtConfig())
    {
        return true;
    }
    LOG_ERROR(m_FileLog, TF("[同步管理]创建例程处理失败"));
    return false;
}
//--------------------------------------
void CCenterServer::Exit(void)
{
    if (m_nStatus != STATUSS_NONE)
    {
        LOG_INFO(m_FileLog, TF("[同步管理]退出处理开始!"));
        m_MgrHandler = nullptr;

        UnloadConfig();

        m_nStatus = STATUSS_NONE;
        LOG_INFO(m_FileLog, TF("[同步管理]退出处理完成!"));
    }
}

void CCenterServer::UnloadConfig(void)
{
    m_pConfig    = nullptr;
    m_NetworkPtr = nullptr;

    assert(m_sListenInternal  == 0);

    assert(m_Balance.SvrMap.GetSize()  == 0);
    assert(m_AuthorDB.SvrMap.GetSize() == 0);
    assert(m_Author.SvrMap.GetSize()   == 0);
    assert(m_MasterDB.SvrMap.GetSize() == 0);
    assert(m_Master.SvrMap.GetSize()   == 0);
    //m_pConfig->GetKeyValue().Remove(CServerConfig::CenterServer);

    UnloadExtConfig();
}
//--------------------------------------
bool CCenterServer::Start(void)
{
    if (m_nStatus == STATUSS_INIT)
    {
        LOG_INFO(m_FileLog, TF("[同步管理]启动开始!"));

        if (m_RoutinePtr->Start(this) == false)
        {
            return false;
        }
        if (StartListen() == false)
        {
            return false;
        }

        m_nStatus = STATUSS_RUN;
        LOG_INFO(m_FileLog, TF("[同步管理]启动完成!"));
    }
    return true;
}

bool CCenterServer::StartListen(void)
{
    STR_ADDR strAddr;
    if (m_pConfig->GetServerAddr(CServerConfig::CFG_LOAD_CENTER, CServerConfig::CFG_LOAD_NONE, strAddr) == false)
    {
        LOG_INFO(m_FileLog, TF("[同步管理]监听从配置读取地址信息失败"));
        return false;
    }
    if (m_sListenInternal != 0)
    {
        LOGV_INFO(m_FileLog, TF("[同步管理]监听[%s]:%d地址的Socket已经存在"), *strAddr.strIp, strAddr.usPort);
        return true;
    }
    if (m_pConfig->GetAnyListen() != 0)
    {
        m_sListenInternal = m_NetworkPtr->Create(*this, strAddr.usPort);
    }
    else
    {
        m_sListenInternal = m_NetworkPtr->Create(*this, strAddr.usPort, *strAddr.strIp);
    }
    bool bRet = true;
    if (m_sListenInternal != 0)
    {
        bRet = m_NetworkPtr->Listen(m_sListenInternal);
        LOGV_INFO(m_FileLog, TF("[同步管理]监听[%s]:%d%s"), *strAddr.strIp, strAddr.usPort, bRet ? TF("成功") : TF("失败"));
    }
    else
    {
        LOGV_ERROR(m_FileLog, TF("[同步管理]创建[%s]:%d失败"), *strAddr.strIp, strAddr.usPort);
    }
    return bRet;
}
//--------------------------------------
bool CCenterServer::Pause(bool bPause)
{
    if (bPause && (m_nStatus == STATUSS_RUN))
    {
        m_nStatus = STATUSS_PAUSE;
        LOG_INFO(m_FileLog, TF("[同步管理]暂停服务器连接"));
        m_RoutinePtr->Pause();
        return true;
    }
    else if ((bPause == false) && (m_nStatus == STATUSS_PAUSE))
    {
        m_nStatus = STATUSS_RUN;
        LOG_INFO(m_FileLog, TF("[同步管理]允许服务器连接"));
        m_RoutinePtr->Pause(false);
        return true;
    }
    return false;
}
//--------------------------------------
void CCenterServer::Stop(void)
{
    if (m_nStatus > STATUSS_NONE)
    {
        LOG_INFO(m_FileLog, TF("[同步管理]停止开始!"));
        m_nStatus = STATUSS_STOP;

        m_nServerInfo  = FALSE;
        m_nCommonEvent = FALSE;
        StopListen();
        m_RoutinePtr->Stop();

        m_Server[PAKT_CENTER].Zero();
        m_Server[PAKT_BALANCE].Reset();
        m_Server[PAKT_AUTHORDB].Reset();
        m_Server[PAKT_AUTHOR].Reset();
        m_Server[PAKT_MASTERDB].Reset();
        m_Server[PAKT_MASTER].Reset();
        m_Balance.SvrMap.RemoveAll();
        m_AuthorDB.SvrMap.RemoveAll();
        m_Author.SvrMap.RemoveAll();
        m_MasterDB.SvrMap.RemoveAll();
        m_Master.SvrMap.RemoveAll();

        m_nStatus = STATUSS_INIT;
        LOG_INFO(m_FileLog, TF("[同步管理]停止完成!"));
    }
}

void CCenterServer::StopListen(void)
{
    if (m_sListenInternal != 0)
    {
        m_NetworkPtr->Destroy(m_sListenInternal);
        m_sListenInternal = 0;
        LOG_INFO(m_FileLog, TF("[同步管理]销毁监听Socket"));
    }
}
//--------------------------------------
bool CCenterServer::OnTcpDispatch(const PacketPtr& PktPtr, PTCP_PARAM pTcp)
{
    // 1. PTCP_PARAM->pCache != nullptr时上层可以保存网络层申请的缓存数据
    //    PTCP_PARAM->pCache, PTCP_PARAM->index是网络层申请的缓存数据的起始地址和索引号
    // 2. PTCP_PARAM->pData为当前数据开始地址, PTCP_PARAM->stSize为当前数据大小
    // 3. 如果上层保存缓存, 设置PTCP_PARAM->pData为nullptr通知网络层不要再使用当前缓存
    // 4. 释放缓存使用MObject::sMCFree(index, pCache)
    bool bRet = true;
    switch (PktPtr->GetEvent())
    {
    case PAKE_LINK:
        {
            if (m_nServerInfo != FALSE)
            {
                // 检测id是否重复, 如果需要id唯一的按检测结果返回, true表示id唯一, false表示id重复冲突
                m_RoutinePtr->AddQueue(PAKE_LINK, *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
            bRet = OnServerLink(static_cast<CNETLink*>(PktPtr.Get()), pTcp->sSocket);
        }
        break;
    case PAKE_UPDATE:
        {
            bRet = OnServerUpdate(static_cast<CNETUpdate*>(PktPtr.Get()), pTcp->sSocket);
            if (m_nServerInfo != FALSE)
            {
                m_RoutinePtr->AddQueue(PAKE_UPDATE, *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
            }
        }
        break;
    case PAKE_UNLINK:
        {
            SERVER_UNLINK su;
            bRet = OnServerUnlink(PktPtr.Get(), pTcp->sSocket, su);
            if (m_nServerInfo != FALSE)
            {
                m_RoutinePtr->AddQueue(PAKE_UNLINK, su.utData, pTcp->sSocket);
            }
        }
        break;
    case PAKE_SYNC:
        {   // 重新发送对应服务器信息
            if (PktPtr->GetType() == PAKT_AUTHOR)
            {
                bRet = SendMasterServerInfo(pTcp->sSocket);
            }
            else if (PktPtr->GetType() == PAKT_BALANCE)
            {
                bRet = SendAuthorServerInfo(pTcp->sSocket);
            }
        }
        break;
    case PAKE_SYNCACK:
        {
            DEV_INFO(TF("[同步管理]向%X服务器[%p]同步服务器信息完成"), PktPtr->GetType(), pTcp->sSocket);
        }
        break;
    case PAKE_LIVE:
        {
            CTPAKHeadBase<PAKE_LIVEACK, PAKT_CENTER> LiveAck;
            LiveAck.SetSrvId((USRVID)m_Server[PAKT_CENTER].usId);
            m_NetworkPtr->Send(pTcp->sSocket, LiveAck);
        }
        break;
    default:
        {
            bRet = false;
            if (m_nCommonEvent != FALSE)
            {
                if ((PktPtr->GetEvent() >= PAKE_COMMON_BEGIN) && (PktPtr->GetEvent() <= PAKE_COMMON_END))
                {
                    bRet = m_RoutinePtr->AddQueue((Int)PktPtr->GetEvent(), *PktPtr, reinterpret_cast<ULLong>(pTcp), QUEUE_TYPE_REFCOUNT_TCP);
                }
            }
            if (bRet == false)
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]%p无法识别的%X服务器信令包数据[event=%d]"), pTcp->sSocket, PktPtr->GetType(), PktPtr->GetEvent());
            }
        }
    }
    return bRet;
}

bool CCenterServer::OnServerLink(CNETLink* pLink, Socket sSocket)
{
    switch (pLink->GetType())
    {
    case PAKT_MASTER:
        {
            if (ServerLink<SVR_MASTER_MAP, PAKT_MASTER>(pLink, (ULLong)sSocket, m_Master))
            {
                // 3.设置为业务管理服务器类型
                m_NetworkPtr->SetAttr(sSocket, PAKT_MASTER_CENTER);
                LOGV_INFO(m_FileLog, TF("[同步管理]业务管理服务器[%p]注册"), sSocket);
                // 4.发送注册回执包
                CTPAKHeadBase<PAKE_LINKACK, PAKT_CENTER> LinkAck;
                LinkAck.SetSrvId((USRVID)m_Server[PAKT_CENTER].usId);
                return m_NetworkPtr->Send(sSocket, LinkAck);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]业务管理服务器[%p]注册失败"), sSocket);
            }
        }
        break;
    case PAKT_MASTERDB:
        {
            if (ServerLink<SVR_COMMON_MAP, PAKT_MASTERDB>(pLink, (ULLong)sSocket, m_MasterDB))
            {
                // 3.设置为业务数据服务器类型
                m_NetworkPtr->SetAttr(sSocket, PAKT_MASTERDB);
                LOGV_INFO(m_FileLog, TF("[同步管理]业务数据服务器[%p]注册"), sSocket);
                // 4.发送注册回执包
                CTPAKHeadBase<PAKE_LINKACK, PAKT_CENTER> LinkAck;
                LinkAck.SetSrvId((USRVID)m_Server[PAKT_CENTER].usId);
                return m_NetworkPtr->Send(sSocket, LinkAck);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]业务数据服务器[%p]注册失败"), sSocket);
            }
        }
        break;
    case PAKT_AUTHOR:
        {
            if (ServerLink<SVR_AUTHOR_MAP, PAKT_AUTHOR>(pLink, (ULLong)sSocket, m_Author))
            {
                // 3.刚注册的授权网关服务器发送okay和sync状态的业务管理服务器信息
                SendMasterServerInfo(sSocket);
                // 4.设置为授权网关服务器类型
                m_NetworkPtr->SetAttr(sSocket, PAKT_AUTHOR_CENTER);
                LOGV_INFO(m_FileLog, TF("[同步管理]授权网关服务器[%p]注册"), sSocket);
                // 5.发送注册回执包
                CTPAKHeadBase<PAKE_LINKACK, PAKT_CENTER> LinkAck;
                LinkAck.SetSrvId((USRVID)m_Server[PAKT_CENTER].usId);
                return m_NetworkPtr->Send(sSocket, LinkAck);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]授权网关服务器[%p]注册失败"), sSocket);
            }
        }
        break;
    case PAKT_AUTHORDB:
        {
            if (ServerLink<SVR_COMMON_MAP, PAKT_AUTHORDB>(pLink, (ULLong)sSocket, m_AuthorDB))
            {
                // 3.设置为授权数据服务器类型
                m_NetworkPtr->SetAttr(sSocket, PAKT_AUTHORDB);
                LOGV_INFO(m_FileLog, TF("[同步管理]授权数据服务器[%p]注册"), sSocket);
                // 5.发送注册回执包
                CTPAKHeadBase<PAKE_LINKACK, PAKT_CENTER> LinkAck;
                LinkAck.SetSrvId((USRVID)m_Server[PAKT_CENTER].usId);
                return m_NetworkPtr->Send(sSocket, LinkAck);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]授权数据服务器[%p]注册失败"), sSocket);
            }
        }
        break;
    case PAKT_BALANCE:
        {
            if (ServerLink<SVR_BALANCE_MAP, PAKT_BALANCE>(pLink, (ULLong)sSocket, m_Balance))
            {
                // 3.刚注册的授权均衡服务器发送okay和sync状态的授权网关服务器信息
                SendAuthorServerInfo(sSocket);
                // 4.设置为授权均衡服务器类型
                m_NetworkPtr->SetAttr(sSocket, PAKT_BALANCE);
                // 5.发送注册回执包
                LOGV_INFO(m_FileLog, TF("[同步管理]授权均衡服务器[%p]注册"), sSocket);
                CTPAKHeadBase<PAKE_LINKACK, PAKT_CENTER> LinkAck;
                LinkAck.SetSrvId((USRVID)m_Server[PAKT_CENTER].usId);
                return m_NetworkPtr->Send(sSocket, LinkAck);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]授权均衡服务器[%p]注册失败"), sSocket);
            }
        }
        break;
    default:
        {
            LOGV_WARN(m_FileLog, TF("[同步管理]%p注册信息无法识别的%X服务器信令包数据"), sSocket, pLink->GetType());
        }
    }
    return false;
}

bool CCenterServer::OnServerUpdate(CNETUpdate* pUpdate, Socket sSocket)
{
    bool bRet = false;
    switch (pUpdate->GetType())
    {
    case PAKT_MASTER:
        {
            bRet = ServerUpdate<SVR_MASTER_MAP, PAKT_MASTER>(pUpdate, (ULLong)sSocket, m_Master);
        }
        break;
    case PAKT_MASTERDB:
        {
            bRet = ServerUpdate<SVR_COMMON_MAP, PAKT_MASTERDB>(pUpdate, (ULLong)sSocket, m_MasterDB);
        }
        break;
    case PAKT_AUTHOR:
        {
            bRet = ServerUpdate<SVR_AUTHOR_MAP, PAKT_AUTHOR>(pUpdate, (ULLong)sSocket, m_Author);
        }
        break;
    case PAKT_AUTHORDB:
        {
            bRet = ServerUpdate<SVR_COMMON_MAP, PAKT_AUTHORDB>(pUpdate, (ULLong)sSocket, m_AuthorDB);
        }
        break;
    case PAKT_BALANCE:
        {
            bRet = ServerUpdate<SVR_BALANCE_MAP, PAKT_BALANCE>(pUpdate, (ULLong)sSocket, m_Balance);
        }
        break;
    default:
        {
            LOGV_WARN(m_FileLog, TF("[同步管理]%p更新信息无法识别的%X服务器信令包数据"), sSocket, pUpdate->GetType());
        }
    }
    if (bRet)
    {
        // 发送更新回执包
        CTPAKHeadBase<PAKE_UPDATEACK, PAKT_CENTER> UpdateAck;
        m_NetworkPtr->Send(sSocket, UpdateAck);
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[同步管理]服务器(type=%d)%p更新信息异常"), pUpdate->GetType(), sSocket);
    }
    return bRet;
}

bool CCenterServer::OnServerUnlink(CPAKHeadBase* pUnlink, Socket sSocket, SERVER_UNLINK& su)
{
    bool bRet = false;
    switch (pUnlink->GetType())
    {
    case PAKT_MASTER:
        {
            LOGV_INFO(m_FileLog, TF("[同步管理]业务管理服务器[%p]注销"), sSocket);
            bRet = ServerUnlink<SVR_MASTER_MAP, PAKT_MASTER>(sSocket, m_Master, su);
        }
        break;
    case PAKT_MASTERDB:
        {
            LOGV_INFO(m_FileLog, TF("[同步管理]业务数据服务器[%p]注销"), sSocket);
            bRet = ServerUnlink<SVR_COMMON_MAP, PAKT_MASTERDB>(sSocket, m_MasterDB, su);
        }
        break;
    case PAKT_AUTHOR:
        {
            LOGV_INFO(m_FileLog, TF("[同步管理]授权网关服务器[%p]注销"), sSocket);
            bRet = ServerUnlink<SVR_AUTHOR_MAP, PAKT_AUTHOR>(sSocket, m_Author, su);
        }
        break;
    case PAKT_AUTHORDB:
        {
            LOGV_INFO(m_FileLog, TF("[同步管理]授权数据服务器[%p]注销"), sSocket);
            bRet = ServerUnlink<SVR_COMMON_MAP, PAKT_AUTHORDB>(sSocket, m_AuthorDB, su);
        }
        break;
    case PAKT_BALANCE:
        {
            LOGV_INFO(m_FileLog, TF("[同步管理]授权均衡服务器[%p]注销"), sSocket);
            bRet = ServerUnlink<SVR_BALANCE_MAP, PAKT_BALANCE>(sSocket, m_Balance, su);
        }
        break;
    default:
        {
            LOGV_WARN(m_FileLog, TF("[同步管理]%p注销信息无法识别的%X服务器信令包数据"), sSocket, pUnlink->GetType());
        }
    }
    if (bRet)
    {
        // 3.设置为无效服务器类型
        m_NetworkPtr->SetAttr(sSocket, PAKT_NONE);
        // 4.发送注销回执包
        CTPAKHeadBase<PAKE_UNLINKACK, PAKT_CENTER> UnlinkAck;
        m_NetworkPtr->Send(sSocket, UnlinkAck);
    }
    return bRet;
}
//--------------------------------------
bool CCenterServer::OnTcpAccept(Socket sAccept, Socket sListen)
{
    UNREFERENCED_PARAMETER(sListen);
    assert(sListen == m_sListenInternal);
    if (m_nStatus == STATUSS_RUN)
    {
        UShort  usPort = 0;
        CString strAddr;
        m_NetworkPtr->GetAddr(sAccept, strAddr, usPort);
        DEV_DUMP(TF("[同步管理]服务器[%s]:%d连接完成!"), *strAddr, usPort);
        LOGV_DUMP(m_FileLog, TF("[同步管理]服务器[%s]:%d连接完成!"), *strAddr, usPort);

        m_Server[PAKT_CENTER].IncrTotal();
        return true;
    }
    else
    {
        LOG_WARN(m_FileLog, TF("[同步管理]同步管理处于暂停状态!"));
    }
    return false;
}
//--------------------------------------
bool CCenterServer::OnTcpClose(Socket sSocket, ULLong ullLiveData)
{
    if (m_nStatus == STATUSS_STOP)
    {
        return false;
    }
    if (sSocket == m_sListenInternal)
    {
        m_sListenInternal = 0;
        DEV_WARN(TF("[同步管理]监听关闭, 进入告警状态"));
        LOG_WARN(m_FileLog, TF("[同步管理]监听关闭, 进入告警状态"));

        m_Server[PAKT_CENTER].WarnLoad();
    }
    else
    { // 单个服务器断开
        SERVER_UNLINK su;
        switch (ullLiveData)
        {
        case PAKT_MASTER_CENTER:
            {
                ServerUnlink<SVR_MASTER_MAP, PAKT_MASTER>(sSocket, m_Master, su);
                LOGV_INFO(m_FileLog, TF("[同步管理]业务管理服务器[%p]断开"), sSocket);
            }
            break;
        case PAKT_MASTERDB:
            {
                ServerUnlink<SVR_COMMON_MAP, PAKT_MASTERDB>(sSocket, m_MasterDB, su);
                LOGV_INFO(m_FileLog, TF("[同步管理]业务数据服务器[%p]断开"), sSocket);
            }
            break;
        case PAKT_AUTHOR_CENTER:
            {
                ServerUnlink<SVR_AUTHOR_MAP, PAKT_AUTHOR>(sSocket, m_Author, su);
                LOGV_INFO(m_FileLog, TF("[同步管理]授权网关服务器[%p]断开"), sSocket);
            }
            break;
        case PAKT_AUTHORDB:
            {
                ServerUnlink<SVR_COMMON_MAP, PAKT_AUTHORDB>(sSocket, m_AuthorDB, su);
                LOGV_INFO(m_FileLog, TF("[同步管理]授权数据服务器[%p]断开"), sSocket);
            }
            break;
        case PAKT_BALANCE:
            {
                ServerUnlink<SVR_BALANCE_MAP, PAKT_BALANCE>(sSocket, m_Balance, su);
                LOGV_INFO(m_FileLog, TF("[同步管理]授权均衡服务器[%p]断开"), sSocket);
            }
            break;
        default:
            {
            }
        }
        if (m_nServerInfo != FALSE)
        {
            m_RoutinePtr->AddQueue(PAKE_UNLINK, su.utData, sSocket);
        }
        m_Server[PAKT_CENTER].DecrTotal();
    }
    return true;
}
//--------------------------------------
bool CCenterServer::CheckListen(void)
{
    if (m_sListenInternal == 0)
    {
        if (StartListen() && m_Server[PAKT_CENTER].IsWarnLoad())
        {
            DEV_WARN(TF("[同步管理]监听重开, 尝试消除告警状态"));
            LOG_WARN(m_FileLog, TF("[同步管理]监听重开, 尝试消除告警状态"));
            m_Server[PAKT_CENTER].Clear();
        }
    }
    return true;
}

bool CCenterServer::SyncServersInfo(void)
{
    bool bRet = false;
    bRet = SyncCenterServerInfo()    ? true : bRet;
    bRet = SyncBalanceServerInfo()   ? true : bRet;
    bRet = SyncAuthorDBServerInfo()  ? true : bRet;
    bRet = SyncAuthorServerInfo()    ? true : bRet;
    bRet = SyncMasterDBServerInfo()  ? true : bRet;
    bRet = SyncMasterServerInfo()    ? true : bRet;
    return bRet;
}

bool CCenterServer::SyncCenterServerInfo(void)
{
    if (m_Server[PAKT_CENTER].usStatus == STATUSU_SYNC)
    {
        m_Server[PAKT_CENTER].usStatus = STATUSU_OKAY;
        return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(m_Server + PAKT_CENTER), PAKT_CENTER) == RET_OKAY);
    }
    return false;
}

bool CCenterServer::SyncBalanceServerInfo(void)
{
    if (m_Server[PAKT_BALANCE].usStatus == STATUSU_SYNC)
    {
        m_Server[PAKT_BALANCE].usStatus = STATUSU_OKAY;
        return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(m_Server + PAKT_BALANCE), PAKT_BALANCE) == RET_OKAY);
    }
    return false;
}

bool CCenterServer::SyncAuthorDBServerInfo(void)
{
    if (m_Server[PAKT_AUTHORDB].usStatus == STATUSU_SYNC)
    {
        m_Server[PAKT_AUTHORDB].usStatus = STATUSU_OKAY;
        return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(m_Server + PAKT_AUTHORDB), PAKT_AUTHORDB) == RET_OKAY);
    }
    return false;
}

bool CCenterServer::SyncAuthorServerInfo(void)
{
    if (m_Server[PAKT_AUTHOR].usStatus == STATUSU_SYNC)
    {
        //DEV_INFO(TF("[同步管理]同步授权网关服务器信息给所有授权均衡服务器"));
        bool bRet = false;
        {
            CSyncLockWaitScope scope(m_Author.SvrLock);

            m_Server[PAKT_AUTHOR].usIncr = 0;
            PINDEX index = m_Author.SvrMap.GetFirstIndex();
            while (index != nullptr)
            {
                bRet = SendAuthorServerInfo(index);
            }
            if (bRet)
            {
                m_Author.Update();
                m_Server[PAKT_AUTHOR].usStatus = STATUSU_OKAY;
            }
        }
        if (bRet)
        {
            return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(m_Server + PAKT_AUTHOR), PAKT_AUTHOR) == RET_OKAY);
        }
    }
    return false;
}

bool CCenterServer::SyncMasterDBServerInfo(void)
{
    if (m_Server[PAKT_MASTERDB].usStatus == STATUSU_SYNC)
    {
        m_Server[PAKT_MASTERDB].usStatus = STATUSU_OKAY;
        return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(m_Server + PAKT_MASTERDB), PAKT_MASTERDB) == RET_OKAY);
    }
    return false;
}

bool CCenterServer::SyncMasterServerInfo(void)
{
    if (m_Server[PAKT_MASTER].usStatus == STATUSU_SYNC)
    {
        //DEV_INFO(TF("[同步管理]同步业务管理信息给授权网关服务器"));
        bool bRet = false;
        {
            CSyncLockWaitScope scope(m_Master.SvrLock);

            m_Server[PAKT_MASTER].usIncr = 0;
            PINDEX index = m_Master.SvrMap.GetFirstIndex();
            while (index != nullptr)
            {
                bRet = SendMasterServerInfo(index);
            }
            if (bRet)
            {
                m_Master.Update();
                m_Server[PAKT_MASTER].usStatus = STATUSU_OKAY;
            }
        }
        if (bRet)
        {
            return (m_MgrHandler->OnHandle(PAKE_SYNC, reinterpret_cast<uintptr_t>(m_Server + PAKT_MASTER), PAKT_MASTER) == RET_OKAY);
        }
    }
    return false;
}

bool CCenterServer::SendAuthorServerInfo(Socket sSocket)
{
    bool bRet = true;
    {
        CSyncLockWaitScope scope(m_Author.SvrLock);

        m_Server[PAKT_AUTHOR].usIncr = 0;
        PINDEX index = m_Author.SvrMap.GetFirstIndex();
        // 授权均衡连接, 发送授权网关服务器信息(没有服务器信息也需要发送, 让授权均衡确认已经收到过同步信息)
        do
        {
            bRet = SendAuthorServerInfo(index, sSocket);
        } while (index != nullptr);
    }
    return bRet;
}

bool CCenterServer::SendMasterServerInfo(Socket sSocket)
{
    bool bRet = true;
    {
        CSyncLockWaitScope scope(m_Master.SvrLock);

        m_Server[PAKT_MASTER].usIncr = 0;
        PINDEX index = m_Master.SvrMap.GetFirstIndex();
        // 授权网关连接, 发送业务管理服务器信息(没有服务器信息也需要发送, 让授权网关确认已经收到过同步信息)
        do
        {
            bRet = SendMasterServerInfo(index, sSocket);
        } while (index != nullptr);
    }
    return bRet;
}

bool CCenterServer::SendAuthorServerInfo(PINDEX& index)
{
    CCenterSync Sync;
    CStream& Stream = Sync.Alloc(m_NetworkPtr, true);
    if (Stream.IsWrite())
    {
        UShort usStatus = m_pConfig->GetInfoDump() ? (UShort)(STATUSU_XLINKSYNC | STATUSU_DUMP) : (UShort)STATUSU_XLINKSYNC;
        Int nCount = 0;
        for (; (index != nullptr) && (Stream.Size() >= Stream.Tell() + AUTHOR_ADDR::Length());)
        {
            SVR_AUTHOR_MAP::SVR_MAP_PAIR* pPair = m_Author.SvrMap.GetNext(index);
            nCount += m_Author.Write(Stream, pPair, usStatus) ? 1 : 0;
        }
        if (nCount > 0)
        {
            if (index == nullptr)
            {
                m_Server[PAKT_AUTHOR].usIncr = m_Server[PAKT_BALANCE].usLoad; // 同步发送完成
            }
            Sync.SetServerStatus(m_Server[PAKT_AUTHOR]);
            // 广播到所有授权均衡服务器
            return Sync.BroadcastSend(m_NetworkPtr, SEND_BROADCAST_AS, PAKT_BALANCE);
        }
        return true;
    }
    return false;
}

bool CCenterServer::SendMasterServerInfo(PINDEX& index)
{
    CCenterSync Sync;
    CStream& Stream = Sync.Alloc(m_NetworkPtr, true);
    if (Stream.IsWrite())
    {
        UShort usStatus = m_pConfig->GetInfoDump() ? (UShort)(STATUSU_XLINKSYNC | STATUSU_DUMP) : (UShort)STATUSU_XLINKSYNC;
        Int nCount = 0;
        for (; (index != nullptr) && (Stream.Size() >= Stream.Tell() + MASTER_ADDR::Length());)
        {
            SVR_MASTER_MAP::SVR_MAP_PAIR* pPair = m_Master.SvrMap.GetNext(index);
            nCount += m_Master.Write(Stream, pPair, usStatus) ? 1 : 0;
        }
        if (nCount > 0)
        {
            if (index == nullptr)
            {
                m_Server[PAKT_MASTER].usIncr = m_Server[PAKT_AUTHOR].usLoad; // 同步发送完成
            }
            Sync.SetServerStatus(m_Server[PAKT_MASTER]);
            // 广播到所有授权网关服务器
            return Sync.BroadcastSend(m_NetworkPtr, SEND_BROADCAST_AS, PAKT_AUTHOR_CENTER);
        }
        return true;
    }
    return false;
}

bool CCenterServer::SendAuthorServerInfo(PINDEX& index, Socket sSocket)
{
    CCenterSync Sync;
    CStream& Stream = Sync.Alloc(m_NetworkPtr, true);
    if (Stream.IsWrite())
    {
        Int nCount = 0;
        if (m_Server[PAKT_AUTHOR].usStatus == STATUSU_NONE)
        {
            ++nCount;
        }

        UShort usStatus = m_pConfig->GetInfoDump() ? (UShort)(STATUSU_OKAYSYNC | STATUSU_DUMP) : (UShort)STATUSU_OKAYSYNC;
        for (; (index != nullptr) && (Stream.Size() >= Stream.Tell() + AUTHOR_ADDR::Length());)
        {
            SVR_AUTHOR_MAP::SVR_MAP_PAIR* pPair = m_Author.SvrMap.GetNext(index);
            nCount += m_Author.Write(Stream, pPair, usStatus) ? 1 : 0;
        }
        if (nCount > 0)
        {
            if (index == nullptr)
            {
                m_Server[PAKT_AUTHOR].usIncr = m_Server[PAKT_BALANCE].usLoad; // 同步发送完成
            }
            Sync.SetServerStatus(m_Server[PAKT_AUTHOR]);
            if (m_Server[PAKT_AUTHOR].usStatus == STATUSU_NONE)
            {
                Sync.GetServerStatus().usStatus = STATUSU_UPDATE;
            }
            Sync.Send(sSocket, m_NetworkPtr);
        }
        return true;
    }
    return false;
}

bool CCenterServer::SendMasterServerInfo(PINDEX& index, Socket sSocket)
{
    CCenterSync Sync;
    CStream& Stream = Sync.Alloc(m_NetworkPtr, true);
    if (Stream.IsWrite())
    {
        Int nCount = 0;
        if (m_Server[PAKT_MASTER].usStatus == STATUSU_NONE)
        {
            ++nCount;
        }

        UShort usStatus = m_pConfig->GetInfoDump() ? (UShort)(STATUSU_OKAYSYNC | STATUSU_DUMP) : (UShort)STATUSU_OKAYSYNC;
        for (; (index != nullptr) && (Stream.Size() >= Stream.Tell() + MASTER_ADDR::Length());)
        {
            SVR_MASTER_MAP::SVR_MAP_PAIR* pPair = m_Master.SvrMap.GetNext(index);
            nCount += m_Master.Write(Stream, pPair, usStatus) ? 1 : 0;
        }
        if (nCount > 0)
        {
            if (index == nullptr)
            {
                m_Server[PAKT_MASTER].usIncr = m_Server[PAKT_AUTHOR].usLoad; // 同步发送完成
            }
            Sync.SetServerStatus(m_Server[PAKT_MASTER]);
            if (m_Server[PAKT_MASTER].usStatus == STATUSU_NONE)
            {
                Sync.GetServerStatus().usStatus = STATUSU_UPDATE;
            }
            Sync.Send(sSocket, m_NetworkPtr);
        }
        return true;
    }
    return false;
}
//--------------------------------------
bool CCenterServer::LoadExtConfig(void)
{
    CStringFix strPath;
    m_pConfig->GetServerExtConfig(CServerConfig::CFG_LOAD_CENTER, strPath);

    LOGV_INFO(m_FileLog, TF("[同步管理]ExtConfig=%s"), *strPath);

    CFileReadStream Reader;
    if (Reader.Create(*strPath))
    {
        CKVNode  KVNode;
        CKVStore KVStore;
        if (KVStore.Load(KVNode, Reader))
        {
            if (KVNode.Find(TF("FrameworkRoutine")))
            {
                return LoadExtRoutine(KVNode);
            }
            else
            {
                LOGV_WARN(m_FileLog, TF("[同步管理]无法找到ExtConfig=%s文件内的节点FrameworkRoutine"), *strPath);
            }
        }
        else
        {
            LOGV_WARN(m_FileLog, TF("[同步管理]解析ExtConfig=%s文件内容失败"), *strPath);
        }
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[同步管理]打开ExtConfig=%s文件不存在"), *strPath);
    }

    LOG_INFO(m_FileLog, TF("[同步管理]默认加载同目录下框架例程模块"));
    CStringKey strObjectKey = TF("C");
    strObjectKey += CServerConfig::CenterRoutine;

    CStringKey strModuleKey = CServerConfig::CurFolder;
#if (__PLATFORM_TARGET__ == PLATFORM_TARGET_LINUX)
    strModuleKey += CServerConfig::LibPrefix;
#endif
    strModuleKey += CServerConfig::CenterRoutine;
    strModuleKey += CServerConfig::LibExt;

    return CreateRTTIObject(*strObjectKey, CServerConfig::CenterRoutine, *strModuleKey);
}

bool CCenterServer::LoadExtRoutine(CKVNode& Root)
{
    // {
    //     ...
    //     "FrameworkRoutine":{
    //         "Name": "Center-Routine",
    //         "Object": "Center-Routine class name",
    //         "Module": "Center-Routine module name",
    //     },
    //  ...
    // }
    CKVString strName;
    CKVString strObject;
    CKVString strModule;

    CKVNode& Routine = Root[TF("FrameworkRoutine")];
    Routine[TF("Name")].GetString(strName);
    Routine[TF("Object")].GetString(strObject);
    Routine[TF("Module")].GetString(strModule);
#if (__PLATFORM_TARGET__ == PLATFORM_TARGET_LINUX)
    strModule.Insert(0, CServerConfig::LibPrefix);
#endif
    strModule += CServerConfig::LibExt;

    return CreateRTTIObject(*strObject, *strName, *strModule);
}

bool CCenterServer::CreateRTTIObject(PCXStr pszObject, PCXStr pszName, PCXStr pszModule)
{
    assert(m_RoutinePtr == nullptr);
    if (CObjectTraits::Load<ICommonRoutine>(pszName, pszModule, m_RoutinePtr, pszObject))
    {
        LOGV_INFO(m_FileLog, TF("[同步管理]RTTI load --- Object=%s, Name=%s, Module=%s --- %p"), pszObject, pszName, pszModule, m_RoutinePtr.Get());
        return (m_RoutinePtr->Init() == (UInt)RET_OKAY);
    }
    LOGV_ERROR(m_FileLog, TF("[同步管理]RTTI load --- Object=%s, Name=%s, Module=%s --- Failed!"), pszObject, pszName, pszModule);
    return false;
}

bool CCenterServer::UnloadExtConfig(void)
{
    return UnloadExtRoutine();
}

bool CCenterServer::UnloadExtRoutine(void)
{
    if (m_RoutinePtr != nullptr)
    {
        CString strName = m_RoutinePtr->GetRTTI().GetName();
        m_RoutinePtr->Exit();
        m_RoutinePtr = nullptr;
        CObjectTraits::Unload<ICommonRoutine>(*strName);
        return true;
    }
    return false;
}
